package com.tasm.aop;


import com.tasm.aop.annotation.EventTrack;
import com.tasm.aop.annotation.InsertLog;
import com.tasm.aop.annotation.SingleClick;
import com.tasm.aop.framework.ASMClassVisitor;
import com.tasm.aop.plugins.EventTrackPointcut;

import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * desc   : 切面的调用入口，如果targetPackageName传入为空字符串，或扫描所有的类
 * author : chendaning
 * date   : 6/11/21
 */
public class ASMEngine {

    /**
     * 调用aop
     *
     * @param targetPackageName 目标包名，要被修改的类的包名
     * @param classInputStream  类的输入流
     * @return
     * @throws Exception
     */
    public static byte[] doAspect(String targetPackageName, InputStream classInputStream) throws Exception {
        return doAspect(targetPackageName, new ClassReader(classInputStream));
    }

    /**
     * 调用aop
     *
     * @param targetPackageName 目标包名，要被修改的类的包名
     * @param classBytes        类的二进制数据
     * @return
     * @throws Exception
     */
    public static byte[] doAspect(String targetPackageName, byte[] classBytes) throws Exception {
        return doAspect(targetPackageName, new ClassReader(classBytes));
    }


    /**
     * 调用aop
     *
     * @param targetPackageName 目标包名，要被修改的类的包名
     * @param classFile         类的二进制文件
     * @return
     */
    public static byte[] doAspect(String targetPackageName, File classFile) {
        InputStream is = null;
        byte[] tBytes = null;
        try {
            is = new FileInputStream(classFile);
            tBytes = doAspect(targetPackageName, is);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (Exception e) {

            }
        }
        return tBytes;
    }


    private static byte[] doAspect(String targetPackageName, ClassReader classReader) {
        ClassWriter tClassWrite = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        ASMClassVisitor tASMClassVisitor = new ASMClassVisitor(targetPackageName, Opcodes.ASM5, tClassWrite);
        classReader.accept(tASMClassVisitor, ClassReader.EXPAND_FRAMES);
        byte[] tAspectedClassByte = tClassWrite.toByteArray();
        return tAspectedClassByte;
    }

    public static List<String> mAnnotationList;
    public static Map<String, Long> mSingleClickTime = new HashMap<>();
    static {
        mAnnotationList = new ArrayList<>();
        mAnnotationList.add(EventTrack.class.getName());
        mAnnotationList.add(InsertLog.class.getName());
        mAnnotationList.add(SingleClick.class.getName());
    }

    private static EventTrackPointcut.OnEventTrackCallback mOnEventTrackCallback;
    public static void setmOnEventTrackCallback(EventTrackPointcut.OnEventTrackCallback mOnEventTrackCallback) {
        ASMEngine.mOnEventTrackCallback = mOnEventTrackCallback;
    }

    public static EventTrackPointcut.OnEventTrackCallback getmOnEventTrackCallback() {
        return mOnEventTrackCallback;
    }
}
